package com.example.venue_reservation_service.aop;

import com.example.venue_reservation_service.annotation.Log;
import com.example.venue_reservation_service.domain.VenueLog;
import com.example.venue_reservation_service.service.VenueLogService;
import com.example.venue_reservation_service.vo.Result;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    @Resource
    private VenueLogService venueLogService;

    @Resource
    private ObjectMapper objectMapper;

    @Pointcut("@annotation(com.example.venue_reservation_service.annotation.Log)")
    public void logPointCut() {}

    private Object getRequestBody(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Annotation[][] paramAnnotations = method.getParameterAnnotations();
        Object[] args = joinPoint.getArgs();

        for (int i = 0; i < paramAnnotations.length; i++) {
            for (Annotation annotation : paramAnnotations[i]) {
                if (annotation.annotationType() == RequestBody.class) {
                    return args[i];
                }
            }
        }
        return null;
    }

    private String parseOperationDesc(String desc,
                                      ProceedingJoinPoint joinPoint,
                                      Object requestBody) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();

        // 绑定方法参数
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = signature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < paramNames.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }

        // 绑定请求体（允许空值）
        context.setVariable("body", requestBody);

        // 支持多类型表达式
        return parser.parseExpression(desc, new TemplateParserContext())
                .getValue(context, String.class);
    }

    @Around("@annotation(logAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint, Log logAnnotation) throws Throwable {
        // 获取请求体参数（修正后的方法）
        Object requestBody = getRequestBody(joinPoint);

        VenueLog sysLog = new VenueLog();
        sysLog.setOperationType(logAnnotation.operationType());

        // 传入requestBody到解析方法
        sysLog.setOperationDesc(
           parseOperationDesc(logAnnotation.operationDesc(), joinPoint, requestBody)
        );

        sysLog.setCreateTime(LocalDateTime.now());

        // 用户信息获取（优化判空逻辑）
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
//            sysLog.setUsername(authentication.getName());
        }

        // IP获取（兼容反向代理场景）
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        sysLog.setIp(getClientIp(request));

        // 参数处理（过滤敏感字段）
        Object[] args = joinPoint.getArgs();
//        sysLog.setParams(serializeParams(args));

        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            sysLog.setTime(System.currentTimeMillis() - startTime);
            sysLog.setStatus("SUCCESS");
            Result result1 = objectMapper.readValue(serializeResult(result), Result.class);
            sysLog.setResult(result1.getMessage()); // 记录操作结果信息
            System.out.println(result1);
            return result;
        } catch (Exception e) {
            sysLog.setStatus("FAIL");
            sysLog.setErrorMsg(e.getClass().getSimpleName() + ": " + e.getMessage());
            throw e;
        } finally {
//            System.out.println(sysLog);
            venueLogService.saveLog(sysLog); // 确保异步保存
        }
    }

    // 新增方法：获取真实客户端IP
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip.split(",")[0];
    }

    // 新增方法：安全序列化参数
    private String serializeParams(Object[] args) {
        try {
            return objectMapper.writeValueAsString(args);
        } catch (JsonProcessingException e) {
            return "参数序列化失败";
        }
    }

    // 新增方法：处理返回结果
    private String serializeResult(Object result) {
        if (result == null) return null;
        try {
            return objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            return "结果序列化失败";
        }
    }
}